package com.github.pig.stock.common.logging;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 日志记录
 * JML
 */
@Aspect
@Component
@Slf4j
public class ControllerAspect {


    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *) ||within(@org.springframework.stereotype.Controller *)")
    public void logPoint() {}
    ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<>();

    @Before(value = "logPoint()")
    public void doBeforeInServiceLayer(JoinPoint joinPoint) {
        Map<String, Object> map = new HashMap<String,Object>();
        threadLocal.set(map);
    }
    @After(value = "logPoint()")
    public void doAfterInServiceLayer(JoinPoint jp) {
        try {
            Map<String, Object> map = threadLocal.get();
            map.put("function", jp.getSignature().getDeclaringTypeName()+"."+jp.getSignature().getName());
            map.put("args",getParameters(jp.getArgs()));
            log.info(JSONObject.toJSONString(map));
        } catch (Exception e) {
            log.error("日志切面出错", e);
        }finally {
            threadLocal.remove();
        }
    }

    @Around(value = "logPoint()")
    public Object doAround(ProceedingJoinPoint pj) throws Throwable {
        // result的值就是被拦截方法的返回值
        Object result = pj.proceed();
        Map<String, Object> map =threadLocal.get();
        map.put("result", result);
        return result;
    }

    @AfterThrowing(value = "logPoint()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint,Throwable e) {
        Map<String, Object> map = threadLocal.get();
        log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\' info={}",
                joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(),
                e.getCause() != null ? e.getCause() : "NULL", e.getMessage(), e, JSONObject.toJSONString(map));

    }
    private Object getParameter(Object obj){
        if(obj instanceof HttpServletRequest){
            HttpServletRequest request=(HttpServletRequest)obj;
            JSONObject json=new JSONObject();
            json.put("paramters", request.getParameterMap());
            json.put("client_ip",request.getHeader("x-forwarded-for") == null?request.getRemoteAddr():request.getHeader("x-forwarded-for"));
            json.put("server_ip", request.getLocalAddr());
            json.put("service_url",  request.getHeader("Referer"));
            return json;
        }
        else if(obj instanceof HttpServletResponse ){
            return obj.toString();
        }
        else if(obj instanceof BindingResult){
            return null;
        }
        else{
            try{
                return JSONObject.toJSONString(obj);
            }
            catch(Exception e){
                return obj.toString();
            }
        }
    }
    private List<Object> getParameters(Object [] objs){
        List<Object> list=new ArrayList<>();
        for(Object obj :objs){
            list.add(getParameter(obj));
        }
        return list;
    }
}
